using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using Meebey.SmartIrc4net;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for IrcManager
/// </summary>
public static class IrcManager
{
    public static System.Diagnostics.Process megaHAL;
    public static string fromHAL = "";
    public static string ircChannel = "#mp3punk";
    public static List<string> ircText = new List<string>();
    // make an instance of the high-level API
    public static IrcClient irc = new IrcClient();

    public static void SendIRCMessage(string message)
    {
        irc.SendMessage(SendType.Message, ircChannel, message);
    }
    // this method we will use to analyse queries (also known as private messages)
    public static void OnQueryMessage(object sender, IrcEventArgs e)
    {
        switch (e.Data.MessageArray[0])
        {
            // debug stuff
            case "dump_channel":
                string requested_channel = e.Data.MessageArray[1];
                // getting the channel (via channel sync feature)
                Channel channel = irc.GetChannel(requested_channel);

                // here we send messages
                irc.SendMessage(SendType.Message, e.Data.Nick, "CHANNEL'" + requested_channel + "'");
                irc.SendMessage(SendType.Message, e.Data.Nick, "Name:'" + channel.Name + "'");
                irc.SendMessage(SendType.Message, e.Data.Nick, "Topic:'" + channel.Topic + "'");
                irc.SendMessage(SendType.Message, e.Data.Nick, "Mode:'" + channel.Mode + "'");
                irc.SendMessage(SendType.Message, e.Data.Nick, "Key:'" + channel.Key + "'");
                irc.SendMessage(SendType.Message, e.Data.Nick, "UserLimit: '" + channel.UserLimit + "'");
                // here we go through all users of the channel and show their
                // hashtable key and nickname 
                string nickname_list = "";
                nickname_list += "Users: ";
                IDictionaryEnumerator it = channel.Users.GetEnumerator();
                while (it.MoveNext())
                {
                    string key = (string)it.Key;
                    ChannelUser channeluser = (ChannelUser)it.Value;
                    nickname_list += key + " => " + channeluser.Nick + ", ";
                }
                irc.SendMessage(SendType.Message, e.Data.Nick, nickname_list);
                irc.SendMessage(SendType.Message, e.Data.Nick, "");
                break;
            case "gc":
                GC.Collect();
                break;
            // typical commands
            case "join":
                irc.RfcJoin(e.Data.MessageArray[1]);
                break;
            case "part":
                irc.RfcPart(e.Data.MessageArray[1]);
                break;
            case "die":
                Exit();
                break;
        }
    }
    // this method handles when we receive "ERROR" from the IRC server
    public static void OnError(object sender, ErrorEventArgs e)
    {
        //System.Console.WriteLine("Error: " + e.ErrorMessage);
        Exit();
    }

    // this method will get all IRC messages
    public static void OnRawMessage(object sender, IrcEventArgs e)
    {
        //System.Console.WriteLine("Received: " + e.Data.RawMessage);
    }

    public static void OnChannelMessage(object sender, IrcEventArgs e)
    {
        ircText.Add("(" + e.Data.Channel + ":" + e.Data.Nick + ") " + e.Data.Message);
        // Send to megaHAL
        askHAL(e.Data.Message);
    }

    static IrcManager()
    {
    }


    public static void GoIRC()
    {
        //Thread.CurrentThread.Name = "Main";
        System.Threading.Thread ircThread = new Thread(new ThreadStart(IrcManager.StartIRCThread));
        ircThread.Start();
    }


    public static void StartIRCThread()
    {
        ircChannel = System.Configuration.ConfigurationManager.AppSettings["ircChannel"];
        
        if (System.Configuration.ConfigurationManager.AppSettings["enableAI"].ToString() == "true")
        {
            startHAL(); // start our AI bot routine process if we're supposed to...
        }
        // wait time between messages, we can set this lower on own irc servers
        irc.SendDelay = 200;

        // we use channel sync, means we can use irc.GetChannel() and so on
        irc.ActiveChannelSyncing = true;
        if (ircChannel.Length > 0)
        {
            // here we connect the events of the API to our written methods
            // most have own event handler types, because they ship different data
            irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
            irc.OnError += new ErrorEventHandler(OnError);
            irc.OnRawMessage += new IrcEventHandler(OnRawMessage);
            irc.OnChannelMessage += new IrcEventHandler(OnChannelMessage);

            string[] serverlist;
            // the server we want to connect to, could be also a simple string
            serverlist = new string[] {"irc.shoutcast.com"};
            int port = 6667;
            try
            {
                // here we try to connect to the server and exceptions get handled
                irc.Connect(serverlist, port);
            }
            catch (ConnectionException e)
            {
                // something went wrong, the reason will be shown
                //System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
                Exit();
            }

            try
            {
                // here we logon and register our nickname and so on 
                irc.Login("Macaroni", "SmartIrc4net Test Bot");
                // join the channel
                irc.RfcJoin(ircChannel);

                // spawn a new thread to read the stdin of the console, this we use
                // for reading IRC commands from the keyboard while the IRC connection
                // stays in its own thread
                //new Thread(new ThreadStart(ReadCommands)).Start();

                // here we tell the IRC API to go into a receive mode, all events
                // will be triggered by _this_ thread (main thread in this case)
                // Listen() blocks by default, you can also use ListenOnce() if you
                // need that does one IRC operation and then returns, so you need then 
                // an own loop 
                irc.Listen();

                // when Listen() returns our IRC session is over, to be sure we call
                // disconnect manually
                irc.Disconnect();
            }
            catch (ConnectionException)
            {
                // this exception is handled becaused Disconnect() can throw a not
                // connected exception
                Exit();
            }
            catch (Exception e)
            {
                // this should not happen by just in case we handle it nicely
                //System.Console.WriteLine("Error occurred! Message: " + e.Message);
                //System.Console.WriteLine("Exception: " + e.StackTrace);
                Exit();
            }
        }
    }

    public static void Exit()
    {
        // we are done, lets exit...
        //System.Console.WriteLine("Exiting...");
        System.Environment.Exit(0);
    }

    public static void startHAL()
    {
        megaHAL = new System.Diagnostics.Process();
        megaHAL.StartInfo.FileName = (@System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "/HAL/megahal.exe");
        megaHAL.StartInfo.WorkingDirectory = (@System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "/HAL/");
        megaHAL.StartInfo.UseShellExecute = false;
        megaHAL.StartInfo.CreateNoWindow = false;
        megaHAL.StartInfo.RedirectStandardOutput = true;
        megaHAL.StartInfo.RedirectStandardInput = true;
        megaHAL.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(encoder_OutputDataReceived);
        megaHAL.Start();
        megaHAL.PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal;
        megaHAL.BeginOutputReadLine();

        //string strFrom = "";
        //System.Diagnostics.ProcessStartInfo psi =
        //  new System.Diagnostics.ProcessStartInfo(@System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "/HAL/megahal.exe");
        //psi.WorkingDirectory = (@"F:\apps\megahal\");
        //psi.RedirectStandardOutput = true;
        //psi.RedirectStandardInput = true;
        //psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
        //psi.UseShellExecute = false;
        //megaHAL = psi.p
        //megaHAL.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(encoder_OutputDataReceived);
        //megaHAL = System.Diagnostics.Process.Start(psi);
        //megaHAL.BeginOutputReadLine();
    }

    public static void askHAL(string input)
    {
        if (megaHAL != null)
        {
            System.IO.StreamWriter toHAL = megaHAL.StandardInput;
            // clean up the input a little
            if (input.StartsWith("("))
            {
                // remove the (name) brackets before asking
                input = input.Remove(0, input.IndexOf(")") + 1);
            }

            if ((input.StartsWith("m") || input.StartsWith("M")) && input.IndexOf(":") < 15)
            {
                input = input.Remove(0, input.IndexOf(":"));
            }

            toHAL.WriteLine(input);
            toHAL.WriteLine("");
        }
    }

    static void encoder_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
    {
        string strSend = e.Data.ToString();
        if (strSend.StartsWith("|") || strSend.StartsWith("+"))
        {
            // we'll ignore the intro banner
        }
        else
        {
            if (strSend.StartsWith(">"))
            {
                strSend = strSend.Remove(0, 4);
            }
            SendIRCMessage(strSend);
            ircText.Add("(macaroni) " +strSend);
        }
    }
}